package com.panopset;

import static com.panopset.Util.*;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.panopset.gui.TPanel;
import com.panopset.gui.TypicalDialog;
import com.panopset.io.DirectoryProcessor;
import com.panopset.io.FileProcessor;

/**
 * Implementation details for Util IO functions.
 *
 * @author Karl Dinwiddie
 *
 */
public final class UtilIO {

    /**
     * Do a global replacement on all files in a directory, and its
     * sub-directories.
     *
     * @param directory
     *            Target directory.
     * @param from
     *            From text.
     * @param to
     *            To text.
     */
    public static void globalReplace(final File directory, final String from,
            final String to) {
        new DirectoryProcessor(directory) {

            @Override
            protected void process(final File f) {

                new FileProcessor.Builder().file(f).listener(
                        new FileProcessor.Listener() {

                            private Vector<String> v = new Vector<String>();

                            @Override
                            public void finish(final FileProcessor processor) {
                                StringBuffer sb = new StringBuffer();
                                boolean firstTime = true;
                                for (String s : v) {
                                    if (firstTime) {
                                        firstTime = false;
                                    } else {
                                        sb.append(Strings.getEol());
                                    }
                                    sb.append(s);
                                }
                                saveStringToFile(sb.toString(), f);
                            }

                            @Override
                            public void process(final FileProcessor processor,
                                    final String[] s) {
                                for (String t : s) {
                                    v.add(t.replace(from, to));
                                }
                            }
                        }).construct().exec();
            }
        }
        .exec();
    }

    /**
     * Delete file.
     *
     * @param path
     *            Path to file to delete.
     */
    public static void delete(final String path) {
        if (path == null) {
            return;
        }
        delete(new File(path));
    }

    /**
     * Delete file.
     *
     * @param path
     *            Path to file to delete.
     */
    public static void delete(final File path) {
        if (path == null) {
            return;
        }
        if (!path.exists()) {
            return;
        }
        if (!path.delete()) {
            dspmsg(x("Failed to delete") + " " + getCanonicalPath(path));
        }
    }

    /**
     * Create new file.
     *
     * @param path
     *            Path to new file.
     */
    public static void createNewFile(final String path) {
        if (path == null) {
            return;
        }
        createNewFile(new File(path));
    }

    /**
     * Create new file.
     *
     * @param path
     *            Path to file.
     */
    public static void createNewFile(final File path) {
        if (path == null) {
            return;
        }
        try {
            if (!path.createNewFile()) {
                dspmsg(x("Failed to create") + " " + getCanonicalPath(path));
            }
        } catch (IOException e) {
            log(e);
        }
    }

    /**
     * Make directories for a path.
     *
     * @param path
     *            Path to make directories for.
     */
    public static void mkdirs(final String path) {
        if (path == null) {
            return;
        }
        mkdirs(new File(path));
    }

    /**
     * Make directories for a path.
     *
     * @param path
     *            Path to make directories for.
     */
    public static void mkdirs(final File path) {
        if (path == null) {
            return;
        }
        if (path.exists()) {
            return;
        }
        if (!path.mkdirs()) {
            dspmsg(x("Unable to create path to")
                    + " " + getCanonicalPath(path));
        }
    }

    /**
     * This method will return true if the files are identical, ignoring the
     * kind of return character used.
     *
     * @param one
     *            First file to compare.
     * @param two
     *            Second file to compare.
     * @return true Only if both files exist and are identical.
     */
    public static boolean filesAreSame(final File one, final File two) {
        final boolean[] rtn = new boolean[1];
        rtn[0] = false;
        new FileProcessor.Builder().file(one).file(two).listener(
                new FileProcessor.Listener() {

                    @Override
                    public void finish(final FileProcessor processor) {
                        rtn[0] = true;
                        processor.stop();
                    }

                    @Override
                    public void process(final FileProcessor processor,
                            final String[] s) {
                        if (s.length != 2 || s[0] == null || s[1] == null
                                || !s[0].equals(s[1])) {
                            processor.stop();
                            return;
                        }
                    }
                }).construct().exec();
        return rtn[0];
    }

    /**
     * Load text from resource.
     *
     * @param resourcePath
     *            Resource path.
     * @return Contents of resource as a String.
     */
    public static String loadTextFromResource(final String resourcePath) {
        StringWriter sw = new StringWriter();
        try {
            for (String s : loadLinesFromResource(resourcePath)) {
                sw.append(s);
                sw.append(Strings.getEol());
            }
        } catch (IOException e) {
            log(e);
        }
        return sw.toString();
    }

    /**
     * Return contents of a file as a String.
     *
     * @param fileName
     *            File name.
     * @return String full text of file.
     */
    public static String getFileText(final String fileName) {
        return getFileText(new File(fileName));
    }

    /**
     * Return contents of a file as a String.
     *
     * @param file
     *            File.
     * @return String full text of file.
     */
    public static String getFileText(final File file) {
        StringWriter rtn = new StringWriter();
        boolean firstTime = true;
        if (!file.exists()) {
            return "";
        }
        for (String s : loadFile(file)) {
            if (firstTime) {
                firstTime = false;
            } else {
                rtn.append(Strings.getEol());
            }
            rtn.append(s);
        }
        return rtn.toString();
    }

    /**
     * Load an object from a file.
     *
     * @param clazz
     *            Class type to load.
     * @param file
     *            File to load from.
     * @return Loaded Object.
     */
    public static Object loadObject(final Class<?> clazz, final File file) {
        Object rtn = null;
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        if (file.exists()) {
            try {
                fis = new FileInputStream(file);
                ois = new ObjectInputStream(fis);
                rtn = ois.readObject();
            } catch (ClassNotFoundException ex) {
                // Delete the file if it no longer matches a class.
                delete(file);
            } catch (InvalidClassException ex) {
                log(ex.getMessage());
            } catch (Exception ex) {
                log(x("Failed to load") + ": " + getCanonicalPath(file));
                log(ex);
            } finally {
                try {
                    if (ois != null) {
                        ois.close();
                    }
                    if (fis != null) {
                        fis.close();
                    }
                } catch (Exception ex) {
                    log(ex);
                }
            }
        }
        if (rtn == null) {
            try {
                rtn = clazz.newInstance();
            } catch (Throwable t) {
                log(t);
                return null;
            }
        }
        return rtn;
    }

    /**
     * Save Object to file.
     *
     * @param object
     *            Object to save.
     * @param file
     *            File to save Object to.
     */
    public static void saveObject(final Object object, final File file) {
        if (!file.exists()) {
            File p = file.getParentFile();
            mkdirs(p);
        }
        try {
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(object);
            oos.flush();
            oos.close();
            fos.close();
        } catch (Exception ex) {
            log(x("Failed to save") + ": " + getCanonicalPath(file));
            ex.printStackTrace();
        }
    }

    /**
     * Create parent directories for a file.
     *
     * @param file
     *            File to create parent directories for.
     * @return true if successful.
     */
    public static boolean createParentDirectories(final File file) {
        if (file == null) {
            return false;
        }
        if (!file.exists()) {
            File parentDir = file.getParentFile();
            if (parentDir == null) {
                return false;
            }
            if (parentDir.exists()) {
                return true;
            }
            mkdirs(parentDir);
        }
        return true;
    }

    /**
     * Copy file.
     *
     * @param from
     *            From file.
     * @param to
     *            To file.
     */
    public static void copyFile(final File from, final File to) {
        try {
            mkdirs(to.getParentFile());
            copyStream(new FileInputStream(from), new FileOutputStream(to));
        } catch (Exception ex) {
            log(x("from") + ": " + getCanonicalPath(from));
            log(x("  to") + ": " + getCanonicalPath(to));
            Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Copy file.
     *
     * @param from
     *            From file.
     * @param to
     *            To file.
     * @param encoding
     *            Encoding.
     */
    public static void copyFile(final File from, final File to,
            final String encoding) {
        try {
            mkdirs(to.getParentFile());
            copyStream(new InputStreamReader(new FileInputStream(from),
                    encoding), new OutputStreamWriter(new FileOutputStream(to),
                    encoding));
        } catch (Exception ex) {
            log(x("from") + ": " + getCanonicalPath(from));
            log(x("  to") + ": " + getCanonicalPath(to));
            Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Save String to file.
     *
     * @param str
     *            String to save.
     * @param file
     *            File to save String to.
     */
    public static void saveStringToFile(final String str, final File file) {
        if (!createParentDirectories(file)) {
            return;
        }
        try {
            FileWriter fw = new FileWriter(file);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(str);
            bw.close();
            fw.close();
        } catch (IOException ex) {
            log(x("file") + ": " + getCanonicalPath(file));
            log(ex);
        }
    }

    /**
     * Save bytes to file.
     *
     * @param bytes
     *            Bytes to save.
     * @param file
     *            File to save bytes to.
     */
    public static void saveBytesToFile(final byte[] bytes, final File file) {
        if (!createParentDirectories(file)) {
            return;
        }
        try {
            FileOutputStream fw = new FileOutputStream(file);
            BufferedOutputStream bw = new BufferedOutputStream(fw);
            bw.write(bytes);
            bw.close();
            fw.close();
        } catch (IOException ex) {
            log(x("file") + ": " + getCanonicalPath(file));
            log(ex);
        }
    }

    /**
     * Copy stream.
     *
     * @param inputStream
     *            Input stream.
     * @param outputStream
     *            Output stream.
     * @throws IOException
     *             IO Exception.
     */
    public static void copyStream(final InputStream inputStream,
            final OutputStream outputStream) throws IOException {
        BufferedInputStream is = null;
        if (inputStream instanceof BufferedInputStream) {
            is = (BufferedInputStream) inputStream;
        } else {
            is = new BufferedInputStream(inputStream);
        }
        BufferedOutputStream os = null;
        if (outputStream instanceof BufferedOutputStream) {
            os = (BufferedOutputStream) outputStream;
        } else {
            os = new BufferedOutputStream(outputStream);
        }
        int b;
        while ((b = is.read()) != -1) {
            os.write(b);
        }
        is.close();
        os.flush();
        os.close();
    }

    /**
     * Buffer size.
     */
    private static final int BUFFER_SIZE = 1024;

    /**
     * Copy stream.
     *
     * @param is
     *            Input stream.
     * @param os
     *            Output stream.
     * @throws IOException
     *             IO Exception.
     */
    public static void copyStream(final InputStreamReader is,
            final OutputStreamWriter os) throws IOException {
        char[] buf = new char[BUFFER_SIZE];
        int len;
        while ((len = is.read(buf)) > 0) {
            os.write(buf, 0, len);
        }
        is.close();
        os.flush();
        os.close();
    }

    /**
     * Copy library resource.
     *
     * @param resourcePath
     *            Resource path.
     * @param targetFile
     *            Target file.
     * @throws IOException
     *             IO Exception.
     */
    public static void copyLibraryResource(final String resourcePath,
            final File targetFile) throws IOException {
        try {
            createParentDirectories(targetFile);
            BufferedInputStream bis = new BufferedInputStream(Util.class
                    .getResourceAsStream(resourcePath));
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(targetFile));
            copyStream(bis, bos);
        } catch (IOException ex) {
            log(x("resourcePath") + ": " + resourcePath);
            log(x("targetFile") + ": " + getCanonicalPath(targetFile));
            Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
            throw (ex);
        }
    }

    /**
     * Load a file into an array. This should be done with reasonable sized text
     * files.
     *
     * @param file
     *            File to load.
     * @return array Array to load file in to.
     */
    public static Vector<String> loadFile(final File file) {
        final Vector<String> lines = new Vector<String>();
        if (file == null) {
            log(x("Can not load null file") + ".");
            return lines;
        }
        if (!file.exists()) {
            log(x("File does not exist") + ": " + getCanonicalPath(file));
            return lines;
        }
        new FileProcessor.Builder().fileAndListener(file,
                new FileProcessor.Listener() {

                    @Override
                    public void finish(final FileProcessor processor) {
                        // nothing to do
                    }

                    @Override
                    public void process(final FileProcessor processor,
                            final String[] s) {
                        lines.add(s[0]);
                    }
                }).construct().exec();
        return lines;
    }

    /**
     * Save package resource.
     *
     * @param packagePath
     *            Package path, ie: com.panopset.something
     * @param directoryPath
     *            Directory path, ie: mylocaldrive/something
     * @return File that resource was saved to.
     * @throws IOException
     *             IO Exception.
     */
    public static File savePackageResource(final String packagePath,
            final String directoryPath) throws IOException {
        String target = directoryPath + "/" + packagePath;
        File tf = new File(target);
        copyLibraryResource(packagePath, tf);
        return tf;
    }

    /**
     * Load lines from resource.
     *
     * @param resourcePath
     *            Resource path to a text file.
     * @return Vector of lines.
     * @throws IOException
     *             IO Exception.
     */
    public static Vector<String> loadLinesFromResource(
            final String resourcePath)
            throws IOException {
        Vector<String> rtn = new Vector<String>();
        BufferedInputStream bis = getResourceStream(resourcePath);
        int i = bis.read();
        StringWriter sw = new StringWriter();
        while (i != -1) {
            if (i == Strings.LINE_FEED_VALUE
                    || i == Strings.CARRIAGE_RETURN_VALUE) {
                sw = refreshStringWriter(rtn, sw);
            } else {
                sw.append((char) i);
            }
            i = bis.read();
        }
        addIfPopulated(rtn, sw.toString());
        bis.close();
        return rtn;
    }

    /**
     * Get resource stream.
     *
     * @param resourcePath
     *            Resource path.
     * @return Buffered input stream.
     */
    public static BufferedInputStream getResourceStream(
            final String resourcePath) {
        return new BufferedInputStream(Util.class
                .getResourceAsStream(resourcePath));
    }

    /**
     * Refresh String writer.
     *
     * @param v
     *            String vector to add sw to.
     * @param sw
     *            String writer to add to v.
     * @return New String writer.
     */
    private static StringWriter refreshStringWriter(final Vector<String> v,
            final StringWriter sw) {
        addIfPopulated(v, sw.toString());
        return new StringWriter();
    }

    /**
     * Add if populated.
     *
     * @param v
     *            String vector.
     * @param s
     *            String to add if it is populated.
     */
    public static void addIfPopulated(final Vector<String> v, final String s) {
        if (v == null) {
            return;
        }
        if (s == null) {
            return;
        }
        if (isPopulated(s)) {
            v.add(s);
        }
    }

    /**
     * ie: changeExtension(new
     * File("/home/app/nls/en.properties"),".properties", ".txt").
     *
     * @param f
     *            File to change extensions in
     * @param oldExtension
     *            Old extension.
     * @param newExtension
     *            New extension.
     */
    public static void changeExtension(final File f, final String oldExtension,
            final String newExtension) {
        if (!isPopulated(oldExtension)
                || oldExtension.equals(getExtension(f.getName()))) {
            File n = new File(dropExtension(getCanonicalPath(f)) + "/"
                    + newExtension);
            copyFile(f, n);
            delete(f);
        }
    }

    /**
     * ie: changeExtensions(new File("/home/app/nls"),".properties", ".txt").
     *
     * @param directory
     *            Directory to change extensions in
     * @param oldExtension
     *            Only files with this extension will be changed. If blank or
     *            null, all files affected.
     * @param newExtension
     *            Affected files will get this new extension, with the old
     *            extension, if any, dropped.s
     */
    public static void changeExtensions(final File directory,
            final String oldExtension, final String newExtension) {
        for (File f : directory.listFiles()) {
            if (f.isDirectory()) {
                changeExtensions(f, oldExtension, newExtension);
            } else {
                changeExtension(f, oldExtension, newExtension);
            }
        }
    }

    /**
     * @param prompt
     *            Prompt.
     * @return String from user.
     */
    public static String getStringFromUser(final String prompt) {
        JTextField tf = new JTextField(
                Numbers.Integers.DEFAULT_TEXT_FIELD_WIDTH.getValue());
        TPanel cp = new TPanel.Builder().layout(new FlowLayout()).construct();
        cp.add(tf);
        new TypicalDialog.Builder(prompt).centerPanel(cp).size(
                new Dimension(Numbers.Integers.DEFAULT_DIALOG_WIDTH.getValue(),
                        Numbers.Integers.DEFAULT_DIALOG_HEIGHT.getValue()))
                .construct().getFrame().setVisible(true);
        return tf.getText();
    }

    /**
     * Save panel image to a file.
     *
     * @param f
     *            File.
     * @param c
     *            Panel.
     */
    public static void savePanel2file(final File f, final JPanel c) {
        Dimension sz = c.getSize();
        final BufferedImage image = new BufferedImage(sz.width, sz.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        c.paint(g);
        saveFinishedImage2file(f, image);
    }

    /**
     * Save canvas to file.
     *
     * @param f
     *            File to save canvas image to.
     * @param c
     *            Canvas to save image from.
     */
    public static void saveCanvas2file(final File f, final Canvas c) {
        Dimension sz = c.getSize();
        final BufferedImage image = new BufferedImage(sz.width, sz.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        c.paint(g);
        saveFinishedImage2file(f, image);
    }

    /**
     * Save image to file.
     *
     * @param f
     *            File to save image to.
     * @param i
     *            Image to save to file.
     */
    public static void saveImage2file(final File f, final Image i) {
        final BufferedImage image = new BufferedImage(i.getWidth(null), i
                .getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        g.drawImage(i, 0, 0, null);
        saveFinishedImage2file(f, image);
    }

    /**
     * Save finished image to file.
     *
     * @param f
     *            File to save image to.
     * @param bi
     *            Finished buffered image to save from.
     */
    public static void saveFinishedImage2file(final File f,
            final BufferedImage bi) {
        String path = f.getPath();
        String fileType = path.substring(path.lastIndexOf(".") + 1);
        assert fileType != null && fileType.length() > 0;
        try {
            ImageIO.write(bi, fileType, f);
        } catch (IOException e) {
            dspmsg("Check permissions to " + getCanonicalPath(f));
            log(e);
        }
    }

    /**
     * Get directory from user.
     *
     * @param path
     *            Path to start from.
     * @param prompt
     *            Prompt user.
     * @return Directory chosen, if any.
     */
    public static File getDirectoryFromUser(final File path,
            final String prompt) {
        return getFileFromUser(path, prompt, JFileChooser.DIRECTORIES_ONLY,
                JFileChooser.OPEN_DIALOG);
    }

    /**
     * Get file from user.
     *
     * @param path
     *            Path to start from.
     * @param prompt
     *            Prompt.
     * @param dialogType
     *            JFileChooser dialog type.
     * @return File, if any.
     */
    public static File getFileFromUser(final File path, final String prompt,
            final int dialogType) {
        return getFileFromUser(path, prompt, JFileChooser.FILES_ONLY,
                dialogType);
    }

    /**
     * Get file from user.
     *
     * @param path
     *            Path.
     * @param prompt
     *            Prompt.
     * @param mode
     *            Mode.
     * @param dialogType
     *            Dialog type.
     * @return file. File.
     */
    public static File getFileFromUser(final File path, final String prompt,
            final int mode, final int dialogType) {
        File rtn = null;
        JFileChooser chooser = new JFileChooser();
        chooser.setSelectedFile(new File(getDefaultPath()));
        chooser.setFileSelectionMode(mode);
        chooser.setDialogTitle(prompt);
        chooser.setDialogType(dialogType);
        if (chooser.showOpenDialog(new JFrame())
                == JFileChooser.APPROVE_OPTION) {
            rtn = chooser.getSelectedFile();
            setDefaultPath(getCanonicalPath(rtn.getParentFile()));
        }

        return rtn;
    }


    /**
     * Extract zip file.
     *
     * @param dir
     *            Directory to extract zip file to.
     * @param bis
     *            Input stream that has zip file contents.
     */
    public static void extractZipFile(final File dir,
            final BufferedInputStream bis) {
        try {

            mkdirs(dir);

            if (!dir.isDirectory()) {
                return;
            }

            ZipInputStream zis = new ZipInputStream(bis);
            ZipEntry ze = zis.getNextEntry();

            while (ze != null) {

                if (ze.isDirectory()) {
                    ze = zis.getNextEntry();
                    continue;
                }

                File f = new File(dir + "/" + ze.getName());

                mkdirs(f.getParentFile());

                copyOpenStream(new BufferedInputStream(zis),
                        new BufferedOutputStream(new FileOutputStream(f)));

                zis.closeEntry();

                ze = zis.getNextEntry();
            }

            zis.close();

        } catch (Exception e) {
            log(e);
        }
    }

    /**
     * Copy open stream.
     *
     * @param bis
     *            Buffered input stream.
     * @param bos
     *            Buffered output stream.
     */
    public static void copyOpenStream(final BufferedInputStream bis,
            final BufferedOutputStream bos) {
        boolean done = false;
        try {
            synchronized (bis) {
                synchronized (bos) {
                    byte[] buff = new byte[Numbers.Integers.BUFFER_SIZE
                            .getValue()];
                    while (!done) {
                        int c = bis.read(buff);
                        if (c == -1) {
                            done = true;
                        } else {
                            bos.write(buff, 0, c);
                        }
                    }
                }
            }
            bos.flush();
            bos.close();
        } catch (IOException ex) {
            log(ex);
        }
    }

    /**
     * Get image from file.
     *
     * @param f
     *            File.
     * @return Image.
     */
    public static Image getImageFromFile(final File f) {
        try {
            Image rtn = null;
            if (f == null) {
                log(x("File is null"));
                return null;
            }
            if (!f.exists()) {
                log(getCanonicalPath(f) + " " + x("does not exist") + ".");
                return null;
            }
            if (!f.canRead()) {
                dspmsg(x("Check permissions") + ".");
                log(getCanonicalPath(f));
                return null;
            }
            if (!checkMemory(f.length())) {
                dspmsg(x("Out of memory, please check log for details") + ".");
            }
            dspmsg(x("loading") + " " + f.getName() + " ...");
            rtn = ImageIO.read(f);
            dspmsg(f.getName() + " " + x("loaded") + ".");
            return rtn;
        } catch (IOException e) {
            dspmsg(e.getMessage());
            log(e);
            return null;
        }
    }

    /**
     * Validate that a file exists, and it is not a directory.
     *
     * @param file
     *            File to check.
     * @return boolean true if valid file found
     */
    public static boolean validateFile(final File file) {
        return ((validateExistence(file)) && (file.isFile()));
    }

    /**
     * Validate that a file exists, and that it is a directory.
     *
     * @param dir Directory to check.
     * @return boolean true if valid directory found
     */
    public static boolean validateDirectory(final File dir) {
        if (validateExistence(dir)) {
            if (dir.isDirectory()) {
                return true;
            } else {
                dspmsg(x("File") + " " + getCanonicalPath(dir) + " "
                        + x("is not a directory"));
            }
        } else {
            if (dir == null) {
                return false;
            }
            if (!dir.mkdirs()) {
                Alert.yellow("Failed to create" + ": " + getCanonicalPath(dir));
            }
        }
        return ((validateExistence(dir)) && (dir.isDirectory()));
    }

    /**
     * Validate existence of a file.
     * @param file File to check.
     * @return True if file exists.
     */
    private static boolean validateExistence(final File file) {
        if (file == null) {
            dspmsg(x("file is null"));
            return false;
        }
        if (file.exists()) {
            return true;
        } else {
            dspmsg(x("file") + " " + getCanonicalPath(file) + " "
                    + x("does not exist"));
            return false;
        }
    }

    /**
     * Default path.
     */
    private static String defaultPath;

    /**
     * @return Default path.
     */
    private static String getDefaultPath() {
        if (defaultPath == null) {
            defaultPath = com.panopset.Strings.USER_HOME;
        }
        return defaultPath;
    }

    /**
     * @param path
     *            Default path.
     */
    private static void setDefaultPath(final String path) {
        defaultPath = path;
    }

    /**
     * Prevent instantiation.
     */
    private UtilIO() {
    }
}
